"""
Handler is the class that does the flickr.<method_name> magic.  This also
contains miscellaneous formatting functions for the method help, accessed like
so:

    help(flickr.photos.getSizes.help)

"""

class Handler(object):
    """
    A class that handles pseudo-attributes for making Flickr calls, e.g.:

        flickr.photos.getSizes
    
    is actually an instance of this class.  When you call it like:

        flickr.photos.getSizes()

    It is using the .__call__() method of this class.

    Try:
    
        help(flickr.photos.getSizes.help)

    for help on a specific function (might be easier than using the Flickr API
    webpage at http://www.flickr.com/services/api/).

    """
    def __init__(self, flickr, method):
        self.flickr = flickr
        self.method = method

    def __call__(self, *args, **kwargs):
        params = {'method':self.method}
        params.update(kwargs)
        return self.flickr._call(url=self.flickr['rest_url'], params=params)

    @property
    def __members__(self):
        # tab-autocompletion
        methods = self.flickr._get_methods()
        methods = [x for x in methods if x.startswith(self.method + '.')]
        methods = [x.replace(self.method + '.','') for x in methods]
        return methods

    def trait_names(self):
        # tab-completion for ipython
        return self.__members__

    def __getattr__(self, name):
        if name[0] == '_':
            raise AttributeError, name
        return Handler(self.flickr, self.method + "." + name)

    def get_help(self):
        response = self.flickr.reflection.getMethodInfo(method_name=self.method)
        return format_method_info(response)

    @property
    def help(self):
        class FlickrMethod(object):
            __doc__ = self.get_help()
        return FlickrMethod

def indent(text, indent_str="\t"):
    return '\n'.join(indent_str+line for line in text.split('\n'))

def wrap(text):
    import textwrap

    import re
    whitespace = re.compile("(\s*)")

    result = []
    for line in text.split('\n'):
        wrapped_lines = textwrap.wrap(line)

        if not wrapped_lines:
            result.append('')
            continue

        # match indentation of first line
        indentation = ''
        for index, line in enumerate(wrapped_lines):
            if index == 0:
                match = whitespace.match(line)
                if match:
                    indentation = match.group() + "  "
                continue
            wrapped_lines[index] = indentation + line
        result.extend(wrapped_lines)
    return '\n'.join(result)

def format_method_info(r):
    """
    Format the help page for a method, based on the response given by
    flickr.reflection.getMethodInfo

    """
    m = r['method']
    name = m['name']
    description = m.get('description','')
    needslogin = m.get('needslogin', None) and 'yes' or 'no'
    needssigning = m.get('needssigning', None) and 'yes' or 'no'
    perms = ['no permissions required', 'read', 'write', 'delete'][int(m['requiredperms'])]

    s =  "\nMethod: %s\n\n" % name
    s += "\tDescription: %s\n" % description 
    s += "\tRequires login: %s\n" % needslogin
    s += "\tRequires signing: %s\n" % needssigning
    s += "\tRequired perms: %s\n" % perms

    s += "\nArguments: " + "\n"
    for a in r['arguments']['argument']:
        name = a['name']
        if a['optional'] == '1':
            name = '[' + name + ']'
        s += "\t" + name + ": " + a['_content'] + "\n"

    if m.has_key('response'):
        response = m['response']
    else:
        response = "This method has no particular response, just success or failure."
    response = indent(response)
    s += "\nExample Response: " + "\n" + response + "\n"

    s += "\nErrors:\n"
    for e in r['errors']['error']:
        s += "\t%(code)s: %(message)s\n" % e
        s += "\t\t%(_content)s\n\n" % e
    return wrap(s).encode('utf8')
